package com.ruoyi.common.utils;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysSecurity;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 安全服务工具类
 *
 * @author ruoyi
 */
@Component
public class SecurityUtils {

    private static RedisCache redisCache;
    private static ApplicationContext context;

    @Autowired
    public SecurityUtils(ApplicationContext context) {
        SecurityUtils.context = context; // 存储ApplicationContext以便后续使用
    }

    /**
     * 用户ID
     **/
    public static Long getUserId() {
        try {
            return getLoginUser().getUserId();
        } catch (Exception e) {
            throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取部门ID
     **/
    public static String getDeptId() {
        try {
            return getLoginUser().getDeptId();
        } catch (Exception e) {
            throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取用户账户
     **/
    public static String getUsername() {
        try {
            return getLoginUser().getUsername();
        } catch (Exception e) {
            throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取用户
     **/
    public static LoginUser getLoginUser() {
        try {
            return (LoginUser) getAuthentication().getPrincipal();
        } catch (Exception e) {
            throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 获取Authentication
     */
    public static Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    /**
     * 生成BCryptPasswordEncoder密码
     *
     * @param password 密码
     * @return 加密字符串
     */
    public static String encryptPassword(String password,Long userId) {
        //密码不能为空
        if (StringUtils.isBlank(password)) {
            throw new IllegalArgumentException("rawPassword cannot be null");
        }
        //安全配置不为空
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        if (redisCache == null) {
            redisCache = context.getBean(RedisCache.class); // 延迟加载Bean
        }
        if (redisCache.getCacheObject(Constants.SECURITY_SETTING+userId) != null) {
            SysSecurity sysSecurity = (SysSecurity) redisCache.getCacheObject(Constants.SECURITY_SETTING+userId);
            if (sysSecurity != null) {
                //密码弱口令校验是否开启
                if (sysSecurity.getPwdIsWeak() != null && sysSecurity.getPwdIsWeak()) {
                    //获取密码强度策略
                    //获取密码最小和最大长度
                    Integer pwdMinLength = sysSecurity.getPwdMinLength();
                    Integer pwdMaxLength = sysSecurity.getPwdMaxLength();
                    //获取密码复杂度策略
                    String pwdComplexity = sysSecurity.getPwdComplexity();
                    String[] pwdComplexityArray = pwdComplexity.split(",");
                    //密码复杂度（密码必须包含字母和数字 0, 密码中字母必须包含大小写 1, 密码中必须包含特殊符号 2
                    return isValidPassword(password, pwdMinLength, pwdMaxLength, pwdComplexityArray, passwordEncoder);
                }
            }
        }
        return passwordEncoder.encode(password);
    }

    /**
     * 生成BCryptPasswordEncoder密码
     *
     * @param password 密码
     * @return 加密字符串
     */
    public static String encryptPassword(String password) {
        //密码不能为空
        if (StringUtils.isBlank(password)) {
            throw new IllegalArgumentException("rawPassword cannot be null");
        }
        //安全配置不为空
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        if (redisCache == null) {
            redisCache = context.getBean(RedisCache.class); // 延迟加载Bean
        }
        return passwordEncoder.encode(password);
    }

    public static String isValidPassword(String password, int minLength, int maxLength, String[] pwdComplexityArray, BCryptPasswordEncoder passwordEncoder) {
        if (password.length() < minLength || password.length() > maxLength) {
            throw new IllegalArgumentException("密码长度不符合要求");
        }
        if (pwdComplexityArray.length > 0) {
            for (String pwdComplexity : pwdComplexityArray) {
                if (pwdComplexity.equals("0")) {
                    // 校验密码中必须包含字母和数字
                    if (!containsLetterAndDigit(password)) {
                        throw new IllegalArgumentException("校验密码中必须包含字母和数字");
                    }
                } else if (pwdComplexity.equals("1")) {
                    // 校验密码中字母必须包含大小写
                    if (!containsUpperAndLower(password)) {
                        throw new IllegalArgumentException("校验密码中字母必须包含大小写");
                    }
                } else if (pwdComplexity.equals("2")) {
                    // 校验密码中必须包含特殊符号
                    if (!containsSpecialChar(password)) {
                        throw new IllegalArgumentException("校验密码中必须包含特殊符号");
                    }
                }
            }
        }
        return passwordEncoder.encode(password);
    }

    // 校验密码中是否包含字母和数字
    private static boolean containsLetterAndDigit(String password) {
        boolean hasLetter = false;
        boolean hasDigit = false;

        for (char c : password.toCharArray()) {
            if (Character.isLetter(c)) {
                hasLetter = true;
            }
            if (Character.isDigit(c)) {
                hasDigit = true;
            }
            if (hasLetter && hasDigit) {
                return true; // 已经包含字母和数字
            }
        }
        return false;
    }

    // 校验密码中是否包含大小写字母
    private static boolean containsUpperAndLower(String password) {
        boolean hasUpper = false;
        boolean hasLower = false;

        for (char c : password.toCharArray()) {
            if (Character.isUpperCase(c)) {
                hasUpper = true;
            }
            if (Character.isLowerCase(c)) {
                hasLower = true;
            }
            if (hasUpper && hasLower) {
                return true; // 已经包含大小写字母
            }
        }
        return false;
    }

    // 校验密码中是否包含特殊符号
    private static boolean containsSpecialChar(String password) {
        // 使用正则表达式判断是否包含特殊符号
        Pattern pattern = Pattern.compile("[^a-zA-Z0-9]");
        Matcher matcher = pattern.matcher(password);
        return matcher.find(); // 如果找到特殊符号则返回true
    }

    /**
     * 判断密码是否相同
     *
     * @param rawPassword     真实密码
     * @param encodedPassword 加密后字符
     * @return 结果
     */
    public static boolean matchesPassword(String rawPassword, String encodedPassword) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    /**
     * 是否为管理员
     *
     * @param userId 用户ID
     * @return 结果
     */
    public static boolean isAdmin(Long userId) {
        return userId != null && 1L == userId;
    }
}
